/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package modelo;

import java.util.Set;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
/**
 *
 * @author Diego Anzola
 */
public class Spaghetti {
    
    private Set<Punto> conjuntoInicial;
    private Set<Punto> conjuntoGenerado;
    private Set<SegmentoLinea> segmentosCerrados;
    private List<SegmentoLinea> segmentosIniciales=new ArrayList<SegmentoLinea>();
    private List<PoliLinea> spaghettis=new ArrayList<PoliLinea>();
    
    public void setSegmentosCerrados(Set<SegmentoLinea> pSegmentos)
    {
        segmentosCerrados = pSegmentos;
    }

    public void setConjuntoInicial(Set<Punto> pPuntos)
    {
        conjuntoInicial = pPuntos;
    }
    
    public List<PoliLinea> getSpaguettis()
    {
        return spaghettis;
    }

    /**
     * Este método es el ingreso al desarrollo del algoritmo.  Toma como base los segmentos
     * de recta resultantes después de eliminar los pelos en el dominio geométrico.
     * Hace un llamado al método enviarCiclosMayores
     */
    public void enviarProcesoInicial()
    {
        Iterator<SegmentoLinea> recorrido = segmentosCerrados.iterator();
        if(recorrido.hasNext())
        {
            SegmentoLinea nuevo = recorrido.next();
            enviarCiclosMayores(nuevo);
        }
    }

    /**
     * Esta función se encarga de verificar si ya se han recorrido todos los puntos del
     * conjunto se segmentos inicial, no es así sigue iterando recursivamente.
     * 
     * @param pSegmento
     */
    public void enviarCiclosMayores(SegmentoLinea pSegmento)
    {
        int k = generarSpaghetti(pSegmento);
        if(k>=0)
        {
            conjuntoGenerado = spaghettis.get(k).toConjuntoPuntos();
            conjuntoInicial = Punto.removerPuntos(conjuntoInicial, conjuntoGenerado);
        }
        if(conjuntoInicial.size()>0)
        {
            Iterator<Punto> recorrido = conjuntoInicial.iterator();
            if(recorrido.hasNext())
            {
                Punto nPunto = recorrido.next();
                SegmentoLinea nSegmento = SegmentoLinea.puntoIncidente(segmentosCerrados, nPunto);
                enviarCiclosMayores(nSegmento);
            }
        }
    }

    public void imprimirSpaghettis()
    {
        Iterator<PoliLinea> recorrido = spaghettis.iterator();
        int k = 0;
        while(recorrido.hasNext())
        {
            k++;
            recorrido.next().imprimirPoliLinea("Spaghetti "+k);
        }
    }

    /**
     * Esta función llama la función para realizar el primer recorrido en la generación
     * del spaguetti, si encuentra un anillo simple lo agrega al listado de spaghettis.
     * 
     * @param arcoInicial
     * @return
     */
    public int generarSpaghetti(SegmentoLinea arcoInicial)
    {
        List<SegmentoLinea> recorridoArcos = new ArrayList<SegmentoLinea>();
        recorridoArcos.add(arcoInicial);
        recorridoArcos = realizarRecorridoInicial(arcoInicial, recorridoArcos,arcoInicial.getFin(),arcoInicial.getOrigen());
        if(recorridoArcos==null)
            return -1;
        else
        {
            int k = spaghettis.size();
            PoliLinea pNueva = PoliLinea.toPoliLinea(recorridoArcos);
            if(pNueva.esArea())
            {
                spaghettis.add(pNueva);
                return k;
            }
            else return -1;
        }
    }

    /**
     * Este metodo recibe realiza un recorrido iterativo y recursivo en búsqueda
     * de un anillo simple, si encuentra que existen puntos que son incidentes
     * con varios segmentos de recta, es decir que no es un anillo simple realiza
     * un llamado a la función realizarRecorrido encargada de este caso.
     *
     * @param arcoInicial segmento de recta de referencia
     * @param anteriores Listado de segmentos  que conformaran el spaghetti
     * @param puntoInicio Punto de referencia donde se busca el siguiente segmento
     * @param puntoPartidaGeneral Punto de partida del spaghetti
     * @return si logra armar un anillo simple genera el listado de segmentos que lo
     * conforman
     */
    public List<SegmentoLinea> realizarRecorridoInicial(SegmentoLinea arcoInicial,List<SegmentoLinea> anteriores,Punto puntoInicio,Punto puntoPartidaGeneral)
    {
        Set<SegmentoLinea> incidentes = SegmentoLinea.segmentosPuntoFinal(segmentosCerrados,arcoInicial,puntoInicio);
        //Si tiene varios caminos
        if(incidentes.size()>1)
        {
            segmentosIniciales.add(arcoInicial);
            Iterator<SegmentoLinea> recorrido = incidentes.iterator();
            while(recorrido.hasNext())
            {
                SegmentoLinea nuevo = recorrido.next();
                if(!SegmentoLinea.existeEnListaSegmentos(nuevo,segmentosIniciales))
                {
                    segmentosIniciales.add(nuevo);
                    List<SegmentoLinea> recorridoArcos = new ArrayList<SegmentoLinea>();
                    recorridoArcos.add(nuevo);
                    realizarRecorrido(nuevo, recorridoArcos,nuevo.getFin(),nuevo.getOrigen());
                }
            }
            return null;
        }
        Iterator<SegmentoLinea> recorrido = incidentes.iterator();
        if(recorrido.hasNext())
        {
            SegmentoLinea siguiente = recorrido.next();
            if(!SegmentoLinea.existeEnListaSegmentos(siguiente,anteriores))
            {
                Punto envio = siguiente.getFin();
                if(envio.esIgual(puntoInicio))
                    envio = siguiente.getOrigen();
                anteriores.add(siguiente);
                if(!envio.esIgual(puntoPartidaGeneral))
                {
                    realizarRecorridoInicial(siguiente,anteriores,envio,puntoPartidaGeneral);
                }
            }
        }
        return anteriores;
    }

    public void eliminarRepetidos()
    {
        for(int i=0;i<spaghettis.size();i++)
        {
            PoliLinea nueva1 = spaghettis.get(i);
            for(int j=0;j<spaghettis.size();j++)
            {
                PoliLinea nueva2 = spaghettis.get(j);
                if(nueva1.esIgual(nueva2) && i!=j)
                {
                    nueva1.imprimirPoliLinea("S"+i);
                    System.out.print("es igual a");
                    nueva2.imprimirPoliLinea("S"+j);
                    spaghettis.remove(j);
                }
            }
        }
    }

    /**
     * Realiza el recorrido iterativo y recursivo por los segmentos de recta del conjunto
     * se segmentos inicial.  Si encuentra que en un punto existen varios caminos los
     * recorre todos recursivamente, pero continua en su propia búsqueda por el segmento
     * que se encuentra con el ángulo menor en sentido contrario a las manecillas del
     * reloj, para esto utiliza la función seleccionar segmento siguiente.  Cuando encuentra
     * el punto de partida general significa que encontró un spaghetti y lo agrega
     * al listado global.
     *
     * @param arcoInicial segmento de recta de referencia
     * @param anteriores Listado de segmentos  que conformaran el spaghetti
     * @param puntoInicio Punto de referencia donde se busca el siguiente segmento
     * @param puntoPartidaGeneral Punto de partida del spaghetti
     */
    public void realizarRecorrido(SegmentoLinea arcoInicial,List<SegmentoLinea> anteriores,Punto puntoInicio,Punto puntoPartidaGeneral)
    {
        Set<SegmentoLinea> incidentes = SegmentoLinea.segmentosPuntoFinal(segmentosCerrados,arcoInicial,puntoInicio);
        if(incidentes.size()>1)
        {
            segmentosIniciales.add(arcoInicial);
            Iterator<SegmentoLinea> recorrido = incidentes.iterator();
            while(recorrido.hasNext())
            {
                SegmentoLinea nuevo = recorrido.next();
                if(!SegmentoLinea.existeEnListaSegmentos(nuevo,segmentosIniciales))
                {
                    segmentosIniciales.add(nuevo);
                    List<SegmentoLinea> recorridoArcos = new ArrayList<SegmentoLinea>();
                    recorridoArcos.add(nuevo);
                    realizarRecorrido(nuevo, recorridoArcos,nuevo.getFin(),nuevo.getOrigen());
                }
            }
        }
        SegmentoLinea siguiente = arcoInicial.seleccionarSegmentoSiguiente(incidentes,anteriores);
        if(siguiente!=null)
        {
            if(!SegmentoLinea.existeEnListaSegmentos(siguiente,anteriores))
            {
                Punto envio = siguiente.getFin();
                if(envio.esIgual(puntoInicio))
                    envio = siguiente.getOrigen();
                anteriores.add(siguiente);
                if(!envio.esIgual(puntoPartidaGeneral))
                {
                    realizarRecorrido(siguiente,anteriores,envio,puntoPartidaGeneral);
                }
                else
                {
                    PoliLinea nPoli = PoliLinea.toPoliLinea(anteriores);
                    if(nPoli.esArea())
                    {
                        spaghettis.add(nPoli);
                        conjuntoGenerado = nPoli.toConjuntoPuntos();
                        conjuntoInicial = Punto.removerPuntos(conjuntoInicial, conjuntoGenerado);
                    }
                }
            }
        }
    }

}
